#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <unistd.h>
#include <syslog.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <pthread.h>

#include "icar.h"
#include "icar_log.h"
#include "icar_msg.h"
#include "icar_utils.h"
#include "icar_thread.h"
#include "icar_sock.h"
#include "icar_conf.h"

extern fdsets_t *firstfdsets;
extern pthread_mutex_t client_fdsets_mutex;
extern int debuglevel;	/* 高度级别，在4 ～ 10 之间，可以打印出大部分调试信息，需要idaemon = 0 */
extern int idaemon;		/* 0: 在终端运行，调试使用。1: 进行守护进程 */
extern int icar_port;	/* 服务器端口 默认为 60000*/
int servfd;				/* 服务器描述符 */

/* 
   子进程退出时的信号处理函数 
 */
void sigchild_handler(int s)
{
	int status;
	pid_t rc;

	icar_daemon(LOG_DEBUG, "Handler for SIGCHLD called. Trying to reap a child");
	while ((rc = waitpid(-1, &status, WNOHANG)) >= 0);

	icar_daemon(LOG_DEBUG, "Handler for SIGCHLD reaped child");
}



/* 
   程序异常时的退出函数
 */
void
termination_handler(int s)
{
	static pthread_mutex_t sigterm_mutex = PTHREAD_MUTEX_INITIALIZER;

	icar_daemon(LOG_INFO, "Handler for termination caught signal %d", s);

	if (pthread_mutex_trylock(&sigterm_mutex)) {
		icar_daemon(LOG_INFO, "Another thread already began global termination handler. I'm exiting");
		pthread_exit(NULL);
	} else {
		icar_daemon(LOG_INFO, "Cleaning up and exiting");
	}

	exit(s == 0 ? 1 : 0);

}


/*
   信号初始化函数
  */
static void
init_signals(void)
{
	struct sigaction sa;

	icar_daemon(LOG_DEBUG, "Initializing signal handlers");

	sa.sa_handler = sigchild_handler;
	sigemptyset(&sa.sa_mask);
	sa.sa_flags = SA_RESTART;
	if (sigaction(SIGCHLD, &sa, NULL) == -1) {
		icar_daemon(LOG_ERR, "sigaction() : %s", strerror(errno));
		exit(1);
	}

	sa.sa_handler = SIG_IGN;
	if (sigaction(SIGPIPE, &sa, NULL) == -1) {
		icar_daemon(LOG_ERR, "sigaction(): %s", strerror(errno));
		exit(1);
	}

	sa.sa_handler = termination_handler;
	sigemptyset(&sa.sa_mask);
	sa.sa_flags = SA_RESTART;

	if (sigaction(SIGTERM, &sa, NULL) == -1) {
		icar_daemon(LOG_ERR, "sigaction(): %s", strerror(errno));
		exit(1);
	}

	if (sigaction(SIGQUIT, &sa, NULL) == -1) {
		icar_daemon(LOG_ERR, "sigaction(): %s", strerror(errno));
		exit(1);
	}

	if (sigaction(SIGINT, &sa, NULL) == -1) {
		icar_daemon(LOG_ERR, "sigaction(): %s", strerror(errno));
		exit(1);
	}
}

/*
   处理连接上服务器的终端设备
Paramters:
	fd : accept函数返回的客户端文件描述符
  */
static void icar_handle_connection(int fd)
{
	fdsets_t *fds;
	pthread_t tid;
	int result;

	/*
	   firstfdsets： 全局变量，fdsets_t结构体，可用描述符的存储位置
	 */
	fds = firstfdsets;

	LOCK_CLIENT_FDS();
	/* 
	   检查现有fdsets_t结构体是否有空闲的描述符存储空间，
	   即存在fdsets_t.fdsets[index] == -1;
	 */
	for (fds = firstfdsets; fds; fds = fds->next) {
		if (fds->index < ARRAY_SIZE(fds->fdsets)) {
			fds->fdsets[fds->index] = fd;
			FD_SET(fd, &fds->allset);
			icar_daemon(LOG_DEBUG, "Add new socket to fds[%d]: %d", fds->index, fd);
			fds->index++;
			UNLOCK_CLIENT_FDS();
			return;
		}
	}
	UNLOCK_CLIENT_FDS();

	/*
	   如果没有可用fdsets_t结构体，动态分配
	   并开启一个线程用于处理这些终端
	 */
	if (fds == NULL) {
		fds = icar_new_fdset();
		LOCK_CLIENT_FDS();
		fds->fdsets[0] = fd;
		icar_daemon(LOG_DEBUG, "Add new socket to fds[%d]: %d", fds->index, fd);
		fds->index++;
		FD_SET(fd, &(fds->allset));
		icar_fdset_list_append(fds);
		UNLOCK_CLIENT_FDS();
		result = pthread_create(&tid, NULL, (void *)thread_msg, (void *)fds);
		if (result != 0)
			icar_die(_("FATAL: Failed to create a new thread message - exiting"));
		pthread_detach(tid);
		
	}
}


/*
   程序的主循环函数
 */
static void
icar_loop()
{
	int connfd;
	/* 	
		创建平台服务器
	 */
	servfd = icar_create_server(SOCK_STREAM, icar_port, NULL);
	if (servfd < 0)
	{
		icar_daemon(LOG_ERR, "Create server failed");
		exit(1);
	}
	icar_daemon(LOG_DEBUG, "Create obd server sucess: %d", servfd);

	while (1) {
		icar_daemon(LOG_DEBUG, "Begain to wait new client connection");
		/* 
		   icar_get_connection(int fd, struct timeval *);
		   监听等待终端连接
		   connfd 为终端描述符，暂时没有定义终端的相关结构体
		 */
		connfd = icar_get_connection(servfd, NULL);
		if (connfd > 0)
		{
			icar_daemon(LOG_DEBUG, "Get new client connection: %d", connfd);
			/* 
			   icar_handle_connection(int fd);
			   处理新连接的终端
			 */
			icar_handle_connection(connfd);
			icar_daemon(LOG_DEBUG, "Handled new client");
		}
		icar_daemon(LOG_DEBUG, "Wait new connection");
	}
}

int main(int argc, char **argv)
{
	/* 命令行参数解析*/
	icar_read_opts(argc, argv);


	/* 信号初始化 */
	init_signals();

	/* 
	   select最多只能处理1024个文件描述符，为了增加可监听文件描述符的个数，
	   定义了 fdsets_t 结构体，结构体中的整数数组用于存储已连接终端的描述符值,
	   当数量大于1024时，程序重新分配一个fdsets_t结构体，以便处理更多的终端
	   当某一个fdsets_t结构体的描述符全部无效时，从程序中删除
	 */
	icar_init_fdset();

	if (idaemon) {
		icar_daemon(LOG_INFO, "Forking into background");
		switch (fork()) {
			case 0:
				setsid();
				icar_loop();
				break;

			default:
				exit(0);
				break;
		}
	} else {
		icar_debug("Enter main loop function");
		icar_loop();
	}

	return 0;
}
